/*
 * Funny Language - a free style programming language.
 * Copyright (C) 2015 by fanguangping (fanguangping@163.com)
 * tree.c
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "tree.h"
#include "../base/cmemory.h"

Tree *alloc_tree() {
	return (Tree *) sys_malloc(sizeof(Tree));
}

TreeNode *alloc_tree_node() {
	TreeNode *result = (TreeNode *) sys_malloc(sizeof(TreeNode));
	result->name = NULL;
	result->data = NULL;
	result->parent = NULL;
	result->children = init_queue();
	return result;
}

Tree *init_tree() {
	Tree *tree = alloc_tree();
	tree->root = alloc_tree_node();
	return tree;
}

static TreeNode *find_tree_node(TreeNode *node, const char *name) {
	if (node->name == NULL)
		return NULL;
	if (strcmp(node->name, name) == 0)
		return node;
	QueueNode *qnode = node->children->head;
	TreeNode *tnode = NULL;
	TreeNode *found = NULL;
	while (qnode != NULL) {
		tnode = (TreeNode *) qnode->element;
		found = find_tree_node(tnode, name);
		if (found != NULL) {
			return found;
		}
		qnode = qnode->next;
	}
	return NULL;
}

TreeNode *tree_find(Tree *tree, const char *name) {
	return find_tree_node(tree->root, name);
}

void tree_add(Tree *tree, const char *parentName, const char *name, void *data) {
	if (tree == NULL)
		return;

	TreeNode *node = tree->root;
	TreeNode *element = NULL;

	if (name == NULL)
		return;
	if (parentName != NULL && strcmp(parentName, name) == 0) {
		fprintf(stderr, "Parent cannot equals child: [%s]!", name);
		return;
	}
	if (tree_find(tree, name)) {
		fprintf(stderr, "[%s] already existed!", name);
		return;
	}
	if (parentName == NULL) {
		node->name = name;
		node->data = data;
	} else {
		node = tree_find(tree, parentName);
		if (node != NULL) {
			QueueNode *qnode = node->children->head;
			TreeNode *tnode = NULL;
			while (qnode != NULL) {
				tnode = (TreeNode *) qnode->element;
				if (strcmp(tnode->name, name) == 0) {
					tnode->data = data;
					return;
				}
				qnode = qnode->next;
			}
			element = alloc_tree_node();
			element->name = name;
			element->data = data;
			element->parent = node;
			enqueue(node->children, element);
		}
	}
}
